/* threadtest.cpp
   Created by Garrett Williams GoatbitsSoftware
   version 020808
   licence gpl

   this program is to test each aspect of the GeneralThread class. and work as an example for 
   that class.  The mutex locks are used to prevent the print statements from walking on each
   other.

   watching the output from this program will show how speratic a thread can function.

   Each line should not be independent.  If the mutex is removed from the print statements 
   many of the print lines will be mixed with each other.

   There are three threads.  the main thread, and two sub threads.  The first sub thread is
   stoped and the other two threads are seen to continue to move forward.  Then the first
   thread is restarted.  Then both sub threads are put to sleep for one second.  the second
   thread is interupted and the first thread is allowed to sleep for the full second.  It
   is obsurvable that at one point no output comes from the either sub thread only from the 
   main thread.  Then when the second sub thread is started data apears.  Then when the time out
   is completed the first thread is seen to out put once again.  For the last few interations
   the main thread is paused with a usleep.  (do not use sleep it is not thread safe).
 */

#include <iostream>       /* standard I/O routines                 */
#include "generalthread.hpp"

void* do_loop(void* data);

using namespace GeneralThread_NS;

class TestThread : public GeneralThread
{
    public:
        TestThread(GeneralMutex &gm):GeneralThread(gm),_counter(0){}
        int counter(){return _counter;}
        void counter(int ){_counter++;}
    private:
        int _counter;
    protected:
        void process(void *th)  // user defined process.
        {
            do_loop(th);
        }
        void timeInterupted() // define what todo when time runs out.
        {
            lock();
            std::cout << " Time NOT Completed interupted. ############ \n";
            unlock();
        }
        void timeCompleted() // define what todo when time runs out.
        {
            lock();
            std::cout << " Time ran out **********\n";
            unlock();
        }
};


/* function to be executed by the new thread */
void*
do_loop(void* data)
{
    TestThread *pt;
    int me;
    pt = (TestThread*)data;
    me = pt->threadID();

    for (int j=0; j<500000; j++); // just waist time.
    pt->lock();
    std::cout << me << " - thread " << pt->counter() << std::endl;
    pt->unlock();
    pt->counter(0);
}

/* like any C program, program's execution begins in main */
int
main(int argc, char* argv[])
{
    int        thr_id;         /* thread ID for the newly created thread */
    pthread_t  p_thread;       /* thread's structure                     */
    int        a         = 1;  /* thread 1 identifying number            */
    int        b         = 2;  /* thread 2 identifying number            */

    GeneralMutex mutex1;
    TestThread thread(mutex1);
    TestThread thread2(mutex1);
    thread.create((void*)&thread);
    thread2.create((void*)&thread2);
    for(int i(0);i<110;i++)
    {
        if(5 ==i)
        {
            mutex1.lock();
            std::cout << b << " cause thread to wait. " << thread.threadID() << std::endl;
            mutex1.unlock();
            thread.stopCond(true);
        }
        if(20 ==i)
        {
            mutex1.lock();
            std::cout << b << " cause thread to go. " << thread.threadID() << std::endl;
            mutex1.unlock();
            thread.condGo();
        }
        if(21 ==i)
        {
            mutex1.lock();
            std::cout << b << " cause thread to timeout. " << thread2.threadID() << std::endl;
            std::cout.flush();
            mutex1.unlock();
            thread2.waitCond(1); // sleep for one second.
            mutex1.lock();
            std::cout << b << " cause thread to timeout. " << thread.threadID() << std::endl;
            std::cout.flush();
            mutex1.unlock();
            thread.waitCond(1); // sleep for one second.
            for (int j=0; j<500000; j++);
        }
        if(85 ==i)
        {
            mutex1.lock();
            std::cout << b << " cause thread to go. " << thread2.threadID() << std::endl;
            std::cout.flush();
            mutex1.unlock();
            thread2.condGo();
        }
        if(100 < i)
        {
            usleep(50000);
        }
        for (int j=0; j<500000; j++);
        mutex1.lock();
        std::cout << b << " - Got " << i << std::endl;
        std::cout.flush();
        mutex1.unlock();
    }
    thread.running(false);
    thread2.running(false);

    return 0;
}
